// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//
#pragma once

#include <pollux/common/memory/byte_stream.h>
#include <pollux/vector/base_vector.h>
#include <pollux/vector/decoded_vector.h>

namespace kumo::pollux::exec {
    struct ContainerRowSerdeOptions {
        /// Used for ex., sorting maps by map keys, when occurring as key.
        bool isKey = true;
    };

    /// Row-wise serialization for use in hash tables and order by.
    class ContainerRowSerde {
    public:
        /// Serializes value from source[index] into 'out'. The value must not be
        /// null.
        static void serialize(
            const BaseVector &source,
            vector_size_t index,
            ByteOutputStream &out,
            const ContainerRowSerdeOptions &options);

        static void
        deserialize(ByteInputStream &in, vector_size_t index, BaseVector *result);

        /// Returns < 0 if 'left' is less than 'right' at 'index', 0 if
        /// equal and > 0 otherwise. flags.nullHandlingMode can be only NullAsValue
        /// and support null-safe equal. Top level rows in right are not allowed to be
        /// null. Note that the assumption for Map is the serialized map entries are
        /// sorted in the order of key to be comparable.
        static int32_t compare(
            ByteInputStream &left,
            const DecodedVector &right,
            vector_size_t index,
            CompareFlags flags);

        /// Returns < 0 if 'left' is less than 'right' at 'index', 0 if
        /// equal and > 0 otherwise. flags.nullHandlingMode can be only NullAsValue
        /// and support null-safe equal. Note that the assumption for Map is the
        /// serialized map entries are sorted in the order of key to be comparable.
        static int32_t compare(
            ByteInputStream &left,
            ByteInputStream &right,
            const Type *type,
            CompareFlags flags);

        /// Returns < 0 if 'left' is less than 'right' at 'index', 0 if
        /// equal and > 0 otherwise. If flags.nullHandlingMode is StopAtNull,
        /// returns std::nullopt if either 'left' or 'right' value is null or contains
        /// a null. If flags.nullHandlingMode is NullAsValue then NULL is considered
        /// equal to NULL. Top level rows in right are not allowed to be null. Note
        /// that the assumption for Map is the serialized map entries are
        /// sorted in the order of key to be comparable.
        static std::optional<int32_t> compareWithNulls(
            ByteInputStream &left,
            const DecodedVector &right,
            vector_size_t index,
            CompareFlags flags);

        /// Returns < 0 if 'left' is less than 'right' at 'index', 0 if
        /// equal and > 0 otherwise. If flags.nullHandlingMode is StopAtNull,
        /// returns std::nullopt if either 'left' or 'right' value is null or contains
        /// a null. If flags.nullHandlingMode is NullAsValue then NULL is considered
        /// equal to NULL. Note that the assumption for Map is the serialized map
        /// entries are sorted in the order of key to be comparable.
        static std::optional<int32_t> compareWithNulls(
            ByteInputStream &left,
            ByteInputStream &right,
            const Type *type,
            CompareFlags flags);

        static uint64_t hash(ByteInputStream &data, const Type *type);
    };
} // namespace kumo::pollux::exec
